struct Coords {
  pub x: i64,
  pub y: i64,
}
fn shift_x_twice(coords: &mut Coords, delta: &i64) {
  coords.x += *delta;
  coords.x += *delta;
}

fn test() {
  let mut a = Coords{x: 10, y: 10};
  let delta_a = 10;
  shift_x_twice(&mut a, &delta_a);  // All good.

  let mut b = Coords{x: 10, y: 10};
  let delta_b = &b.x;
  // shift_x_twice(&mut b, delta_b);  // Compilation failure.
}

fn evil_feeder<T>(input: &mut T, val: T) {
  *input = val;
}

fn test2() {
  // let mut mr_snuggles: & str = "meow! :3";  // mr. snuggles forever!!
  // {
  //     let spike = String::from("bark! >:V").as_ref();
  //     let spike_str:&str = & spike;                // Only lives for the block
  //     evil_feeder(&mut mr_snuggles, &*spike_str);    // EVIL!
  // }
  // println!("{}", mr_snuggles);                     // Use after free?
}

fn test3() {
  let val_i = 1; 

  let ref val_i_ref = val_i;
  let val_i_ref_ = &val_i;
  assert_eq!(val_i_ref, val_i_ref_);

  let mut val_mut_i = 10;

  let ref val_mut_i_ref = val_mut_i;
  let val_mut_i_ref_ = &val_mut_i;
  assert_eq!(val_mut_i_ref, val_mut_i_ref_);

  let ref mut val_mut_i_ref_mut = val_mut_i;
  // let val_mut_i_ref_mut_ = &mut val_mut_i;
  println!("{}", val_i);
  println!("{}", val_i_ref);
  // println!("{}", val_mut_i);
  // println!("{}", val_mut_i_ref);
  println!("{}", val_mut_i_ref_mut);
}

fn test4() {
  let mut val1 = 2;
  let mut val2 = 3;
  let ref mut val2_mut_ref222 = val2;
  // let ref mut val2_mut_ref3333 = val2;
  // let val2_mut_ref4444 = &mut val2;
  let val2_mut_ref5555 = &mut val2;
  // let val2_mut_ref3333 = ref mut val2;
  println!("{}", val2_mut_ref5555);
  // println!("{}", val2_mut_ref222);
  // assert_eq!(val2_mut_ref222, val2_mut_ref5555);
  // println!("{}", val2_mut_ref3333);
  {
    let ref mut val1_ref = val1;
    {
      let ref mut val2_mut_ref = val2;
      // let ref val2_ref = val2;
      {
        *val2_mut_ref = *val1_ref;
        // val2_mut_ref = &mut val1_ref;
      }
    }
  }
}

fn test5() {
  fn _test5_print(value: &mut i32){
    println!("{}", value);
  }
  fn _test5_print2(value: i32){
    println!("{}", value);
  }
  let mut value = 10;
  let mut_value = &mut value;
  _test5_print2(*mut_value);
}

#[cfg(test)]
pub mod tests {
  #[test]
  fn test1() {
      use super::*;
      test();
  }
  #[test]
  fn test2() {
      use super::*;
      test2();
  }
}